package org.study.utils;

import org.study.entity.ModuleXMLConfigEntity;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FileByXML {

    /**
     * 读取XML文件,并返回数据库可以保存的内容
     * 1. 事件驱动，逐行读取，内存占用低但不可回退
     *
     * @param file xml文件路径
     * @throws Exception 异常信息
     */
    public static List<ModuleXMLConfigEntity>  read(String file) throws Exception {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        final List<ModuleXMLConfigEntity> entities = new ArrayList<ModuleXMLConfigEntity>();
        parser.parse(file, new DefaultHandler() {
            private StringBuilder data;
            //层级
            private int level = 0;
            //行号
            private int index = 0;

            private ModuleXMLConfigEntity entity;

            @Override
            public void startDocument() throws SAXException {
                System.out.println("开始解析文档");
                level = 0;
            }

            //xml的起始位置 < 开头的位置
            @Override
            public void startElement(String uri, String localName,
                                     String qName, Attributes attributes) {
                level += 1;
                index += 1;
                entity = new ModuleXMLConfigEntity();
                entity.setKey(qName);
                entity.setLevel(level);
                entity.setRowNum(index);
                entities.add(entity);
                if (attributes.getLength() > 0) {
                    StringBuilder attribute = new StringBuilder();
                    for (int i = 0; i < attributes.getLength(); i++) {
                        attribute.append(attributes.getQName(i));
                        attribute.append("=");
                        attribute.append(attributes.getValue(i));
                        attribute.append("=");
                    }
                    entity.setAttributes(attribute.substring(0, attribute.length() - 1));
                }
//                System.out.println(attributes.getValue(qName));
//                System.out.println("start qName = " + qName + " level = " + level);
                data = new StringBuilder();
            }

            //获取值
            @Override
            public void characters(char[] ch, int start, int length) {
                if (data != null) {
                    data.append(ch, start, length);
                }

            }

            //xml的起始位置 </ 开头的位置
            @Override
            public void endElement(String uri, String localName, String qName) {
                if (entity.getKey().equals(qName)) {
                    entity.setValue(data.toString().trim());
                }
                //层级-1
                level -= 1;
            }

            @Override
            public void endDocument() throws SAXException {
                System.out.println("文档解析结束");
            }
        });
        return entities;
    }

    /**
     * 根据XML的数据，生成XML文件
     * @param entities XML实体数据
     * @param filePath  生成后的文件地址
     * @throws Exception  异常信息
     */
    public static void write(List<ModuleXMLConfigEntity> entities,String filePath) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.newDocument();
        Map<Integer,Element> elementMap = new HashMap<Integer,Element>();
        for (ModuleXMLConfigEntity entity: entities) {
            Element element = write(doc,entity,elementMap.get(entity.getLevel()-1));
            elementMap.put(entity.getLevel(), element);
        }
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        //格式化：间隔4个字符
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        transformer.transform(new DOMSource(doc),
                new StreamResult(new File(filePath)));
    }

    private static Element write(Document doc, ModuleXMLConfigEntity entity, Element pre) {
        //创建节点
        Element element = doc.createElement(entity.getKey());
        if (entity.getValue() != null) {
            //设置节点内容
            element.appendChild(doc.createTextNode(entity.getValue()));
        }
        //设置节点属性
        if (entity.getAttributes() != null) {
            String[] ats = entity.getAttributes().split("=");
            for (int i = 0; i < ats.length; i += 2) {
                element.setAttribute(ats[i], ats[i + 1]);
            }
        }
        //非根节点，在上一级插入
        if (entity.getLevel() > 1 && pre != null) {
            pre.appendChild(element);
        }
        //跟节点
        if (entity.getLevel() == 1) {
            doc.appendChild(element);
        }
        return element;
    }

    public static void testWrite(String path) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.newDocument();

        Element root = doc.createElement("school");
        doc.appendChild(root);

        Element student = doc.createElement("student");
        root.appendChild(student);

        Element name = doc.createElement("name");
        name.appendChild(doc.createTextNode("张三"));
        student.appendChild(name);

        Element age = doc.createElement("age");
        age.appendChild(doc.createTextNode("18"));
        student.appendChild(age);

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(new DOMSource(doc),
                new StreamResult(new File(path + "/output_dom.xml")));
    }

    public static void main(String... args) {
        try {
            String path = "/Users/fujianli/Desktop/Java/test";
            FileUtils.createDirectory(path);
//            write(path);
            // read(path + "/output_dom.xml");
           List<ModuleXMLConfigEntity> entities = read("/Users/fujianli/Desktop/Java/hadoop-install/install/pom.xml");
            write(entities,"/Users/fujianli/Desktop/Java/test/pom.xml");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
